home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Tool Chest / Development Tools & Languages / Dylan Related / Mindy / Mindy 1.2 - Mac PPC / doc / string-extensions.doc < prev   
Encoding:
Text File  |  1995-03-15  |  17.8 KB  |  405 lines  |  [TEXT/MMCC]

  1. The String-extensions Library
  2.  
  3. Copyright (c) 1994  Carnegie Mellon University
  4.  
  5.  
  6. Introduction
  7.  
  8. String-extensions is a library of routines for working with characters
  9. and strings.  String-extensions exports these modules:
  10.    Conversions
  11.       This module consists of various useful conversions involving
  12.       strings.
  13.    Character-type
  14.       This module is a Dylanized version of the C library ctype.h
  15.    String-hacking    
  16.       This module exports miscellanous functions and data structures
  17.       that are useful when working with strings and characters.
  18.    Regular-expressions
  19.       This module contains various functions that deal with regular
  20.       expressions (regexps).
  21.    Substring-search
  22.       This module contains methods for searching for fixed substrings
  23.       rather than general regular expressions.
  24.  
  25.  
  26. The Conversions Module
  27.  
  28. The Conversions module consists of various useful conversions
  29. involving strings.  They are:
  30.  
  31. string-to-integer(string, #key base) => integer [Function]
  32. integer-to-string(integer, #key base) => string [Function]
  33. digit-to-integer(character) => integer          [Function]
  34. integer-to-digit(integer) => character          [Function]
  35.    Base defaults to 10, and is the radix for the number system to
  36.    convert from/to.  Bases below 2 are errors, as are bases above
  37.    36.  When converting from a string, the string must exactly describe a
  38.    number, with no excess characters.  Digit-to-integer will signal an
  39.    error if the digit is non-alphanumeric.  Errors will be signalled
  40.    for all invalid input.
  41.  
  42. as(<string>, character)                         [G.F. Method]
  43.    Turns a character into the appropriate string of length one.
  44.  
  45.  
  46.  
  47. The Character-type Module
  48.  
  49. Character-type is a Dylanized version of the C library ctype.h  It
  50. contains the following functions:
  51.     FUNCTION AND ARG TYPE       RETURNS #t FOR THESE CHARACTERS
  52.      alpha?(character)          a-zA-Z
  53.     digit?(character)       0-9
  54.     alphanumeric?(character)   a-zA-Z0-9
  55.     whitespace?(character)       Space, tab, newline, formfeed,
  56.                    carriage return
  57.     uppercase?(character)       A-Z
  58.     lowercase?(character)       a-z
  59.     hex-digit?(character)       0-9a-f
  60.     punctuation?(character)       ,./<>?;\:"|'[]{}!@#$%^&*()-=_+`~
  61.     graphic?(character)       alphanumeric or punctuation
  62.     printable?(character)       graphic or whitespace
  63.     control?(character)       not printable
  64.  
  65.  
  66.  
  67. String-hacking
  68.  
  69. The String-hacking module exports miscellanous functions and data
  70. structures that are useful when working with strings and characters.
  71.  
  72. add-last(stretchy-sequence, object)             [Generic Function] 
  73.     => stretchy-sequence          
  74. add-last(string, character) => string           [G.F. Method]
  75.    Like add except it's guarenteed to add the character to the
  76.    end of the string.
  77.  
  78. predecessor(character) => character            [Function]
  79.    Get the character before this character.  Equivalent to
  80.       as(<character>, -1 + as(<integer>, character))
  81.  
  82. successor(character) => character               [Function]
  83.    Get the character after this character.  Equivalent to
  84.       as(<character>, 1 + as(<integer>, character))
  85.  
  86. case-insensitive-equal(object1, object2)        [Generic Function]
  87. case-insensitive-equal(string1, string2)        [G.F. Method]
  88. case-insensitive-equal(character1, character2)  [G.F. Method]
  89.    Does a case insensitive equality test.  Methods are provided only
  90.    for strings and characters, not general collections.
  91.  
  92. <character-set>                                 [Sealed Abstract Class]
  93. <case-sensitive-character-set>                  [Class]
  94. <case-insensitive-character-set>                [Class]
  95.    A <character-set> is a non-mutable subclass of <collection>, and is
  96.    conceptually an unordered set of characters.  Dylan collection
  97.    elements always have keys, so to fit sets into Dylan, the key of an
  98.    element of a character set is the element itself.  There are two
  99.    instantiable subclasses of <character-set>,
  100.    <case-sensitive-character-set> and
  101.    <case-insensitive-character-set>.  <character-set> is not
  102.    instantiable; one must always specify one of the instantiable
  103.    subclasses when creating a character set.
  104.  
  105.    There are two ways of making a character set.  The first is a
  106.    method for make using the description: keyword.  The value that
  107.    follows the description: keyword is a string that describes the set
  108.    using a notation like a regular expression character set, except
  109.    without the '[' and ']' delimiters.  For example,
  110.     make(<case-sensitive-character-set>, description: "a-z")
  111.    would be the set of all lowercase alphabetic characters.
  112.  
  113.    A second way to create character sets is to use an "as" method.
  114.    The as method basically takes a collection of characters and
  115.    discards the keys of these characters.  Example:
  116.     as(<case-insensitive-character-set>,
  117.        "abcdefghijklmnopqrstuvwxyz")
  118.    is again the set of all lowercase alphabetic characters.  It is
  119.    important to realize that the as method does *not* take a
  120.    description:
  121.     as(<case-sensitive-character-set>, "a-z")
  122.    returns the set of 'a', '-', and 'z', not the set of all alphabetic
  123.    characters.
  124.  
  125.    The most useful operation on character sets is member?, which does
  126.    what one would expect.  Another useful operation is the
  127.    forward-iteration-protocol.  This basically calls member? on every
  128.    possible character until it finds a character that is a member of
  129.    the set.  This means that in a <case-insensitive-character-set>,
  130.    both 'a' and 'A' will come up.
  131.  
  132. <byte-character-table>                          [Class]
  133.    A byte-character-table is a vector that uses byte characters as
  134.    indices instead of integers.  The following are equivalent:
  135.       regular-vector[as(<integer>, character)]
  136.       byte-character-table[character]
  137.    <byte-character-table> has absolutely no relation to <table>.  It
  138.    is simply a <mutable-explicit-key-collection>.
  139.  
  140.  
  141.  
  142. Regular-expressions
  143.  
  144. The Regular-expressions module contains various functions that deal
  145. with regular expressions (regexps).  The module is based on Perl
  146. (version 4), and has the same semantics unless otherwise noted.  The
  147. syntax for Perl-style regular expressions can be found on page 103 of
  148. Programming Perl by Larry Wall and Randal L. Schwartz.  There are some
  149. differences in the way String-extensions handles regular expressions.
  150. The biggest difference is that regular expressions in Dylan are case
  151. insensitive by default.  Also, when given an invalid regexp,
  152. String-extensions will produce undefined behavior while Perl would
  153. give an error message.
  154.  
  155. There is some work involved in analyzing a regular expression, and if
  156. the same regexp is used repeatly with different target strings, this
  157. will result in wasted computation.  For this reason, each basic
  158. function in the Regular-expression module comes with a companion
  159. function that makes using a regular expression more efficient when it
  160. is used more than once.  For example, the regexp-replace function has
  161. the make-regexp-replacer companion function.  There is one exception;
  162. the join function has no make-joiner function.  The "make-fooer" will
  163. analyze the regular expression exactly once, and provide a function
  164. that makes use of this pre-analyzed regular expression.  For example,
  165. the following two pieces of code yield the same result:
  166.     regexp-position("This is a string", "is");
  167.  
  168.     let is-finder = make-regexp-positioner("is");
  169.     is-finder("This is a string");
  170.  
  171. However, the second form is more efficient if is-finder is called 
  172. multpile times.
  173.  
  174. regexp-position                                 [Generic Function]
  175.     (big-string, regexp, #key start, end, case-sensitive)
  176.     => variable-number-of-marks-or-#f
  177.  
  178.    This function returns the index of the start of the regular
  179.    expression in the big-string, or #f if the regular expression is
  180.    not found.  As a second value, it returns the index of the end of
  181.    the regular expression in the big-string (assuming it was found;
  182.    otherwise there is no second value).  If there are groups in the
  183.    regular expression, regexp-position will return two more values (a
  184.    start and an end) for each group.  If the subgroup is matched,
  185.    these will be integers.  So
  186.       regexp-position("This is a string", "is");
  187.    returns values(2, 4), and 
  188.       regexp-position("This is a string", "(is)(.*)ing");
  189.    returns values(2, 16, 2, 4, 4, 13), while
  190.       regexp-position("This is a string", "(not found)(.*)ing");
  191.    returns #f.  If the subgroup is not matched, however, both the
  192.    start and the end will be #f.  The marks are always given relative
  193.    to the start of big-start, and not relative to the start: keyword.
  194.  
  195.    Start: and end: specify what part of big-string to look at, and
  196.    they default to the beginning and end of the string, respectively.
  197.    Case-sensitive defaults to false.
  198.  
  199. make-regexp-positioner                          [Generic Function]
  200.     (regexp, #key byte-characters-only, need-marks,
  201.                   maximum-compile, case-sensitive)
  202.     => an anonymous positioner function 
  203.        method (big-string, #key start, end)
  204.    Make-regexp-positioner can return several different types of
  205.    positioners, and it is up to the user to specify what kind of
  206.    positioner the user wants.  By default, it returns a positioner
  207.    that works like regexp-position.  However, if need-marks is #f, it
  208.    may give a positioner that only returns #t or #f, with no marks.
  209.    (And then again, it may still return marks) If byte-characters-only
  210.    is specified, the positioner may only work on big-strings that
  211.    consist only of byte characters (characters whose numerical value
  212.    is between 0 and 255, inclusive).  And if maximum-compile is #t, it
  213.    will take a long time to return a positioner, but the positioner
  214.    will run really fast.
  215.  
  216. regexp-replace                                  [Generic Function]
  217.     (big-string, search-for-regexp, replace-with-string, 
  218.      #key count, case-sensitive, start, end)
  219.     => new-string
  220.    This replaces all occurences of regexp in big-string with
  221.    replace-string.  If count: is specified, it replaces only the first
  222.    count occurences of regexp.  (This is different from Perl, which
  223.    replaces only the first occurence unless /g is specified)
  224.    Replace-string can contain backreferences to the regexp.  For
  225.    instance,
  226.       regexp-replace("The rain in spain and some other text",
  227.                  "the (.*) in (\\w*\\b)", "\\2 has its \\1")
  228.    returns "spain has its rain and some other text".  If the subgroup
  229.    referred to by the backreference was not matched, the reference is
  230.    interpretted as the null string.  For instance,
  231.       regexp-replace("Hi there", "Hi there(, Bert)?", 
  232.              "What do you think\\1?")
  233.    returns "What do you think?" because ", Bert" wasn't found.
  234.  
  235.  
  236. make-regexp-replacer                            [Generic Function]
  237.     (regexp, #key replace-with, case-sensitive)
  238.     => an anonymous replacer function that is either
  239.     method (big-string, #key count, start, end)
  240.     or 
  241.     method (big-string, replace-string, #key count, start, end)
  242.    The first form is returned if the replace-with: keyword isn't
  243.    supplied, otherwise the second form is returned.  (There is no
  244.    efficiency gained by supplying the replace-with string, but it
  245.    might be convenient)
  246.  
  247. translate(big-string, from-string, to-string,   [Generic Function]
  248.       #key delete, start, end) 
  249.     => new-string
  250.    This is equivalent to Perl's tr/// construct.  From-string is a
  251.    string specification of a character set, and to-string is another
  252.    character set.  Translate converts big-string character by
  253.    character, according to the sets.  For instance,
  254.       translate("any string", "a-z", "A-Z")
  255.    will convert "any string" to all uppercase: "ANY STRING".
  256.  
  257.    Like Perl, character ranges are not allowed to be "backwards".  The
  258.    following is not legal:
  259.     translate("any string", "a-z", "z-a")
  260.    (This restriction may be removed in future releases)  Unlike Perl's
  261.    tr///, translate doesn't return the number of characters
  262.    translated.
  263.  
  264.    If delete: is true, any characters in the from-string that don't
  265.    have matching characters in the to-string are deleted.  The
  266.    following will remove all vowels from a string and convert periods
  267.    to commas:
  268.     translate("any string", ".aeiou", ",", delete: #t)
  269.    Delete: is false by default.  If delete: is false and there aren't
  270.    enough characters in the to-string, the last character in the
  271.    to-string is reused as many times as necessary.  The following
  272.    converts several punctuation characters into spaces:
  273.     translate("any string", ",./:;[]{}()", " ");
  274.    Start: and end: indicate which part of the string.  They default to
  275.    the entire string.
  276.  
  277.    Caveats:  Translate is always case sensitive.
  278.  
  279. translate                                       [G.F. Method]
  280.     (big-byte-string, from-byte-string, to-byte-string,
  281.      #key delete, start, end) 
  282.     => new-string
  283.    The only method of translate operates only on byte strings.
  284.  
  285. make-translator                                 [Generic Function]
  286.     (from-string, to-string, #key delete) 
  287.     => an anonymous translator
  288.        method (big-string, #key start, end) => new-string
  289.    Does what you'd expect it to.
  290.  
  291. make-translator                                 [G.F. Method]
  292.     (from-byte-string, to-byte-string, #key delete) 
  293.     => an anonymous translator
  294.        method (big-string, #key start, end) => new-byte-string
  295.    Again, the existing method on make-translator only handles byte
  296.    strings.
  297.  
  298. split                                           [Generic Function]
  299.     (regexp, big-string, #key count, remove-empty-items,
  300.      case-sensitive, start, end)
  301.     => a variable number of strings
  302.    This is like Perl's split function.  It searchs big-string from
  303.    occurences of regexp, and returns substrings that were delimited by
  304.    that regexp.  For instance,
  305.     split("-", "long-dylan-identifier")
  306.    returns values("long", "dylan", "identifier").  Note that what
  307.    matched the regexp is left out.  Remove-empty-items, which defaults
  308.    to true, magically skips over empty items, so that
  309.     split("-", "long--with--multiple-dashes)
  310.    returns values("long", "with", "multiple", "dashes").  Count is the
  311.    maximum number of strings to return.  If there are n strings and
  312.    count is specified, the first count - 1 strings are returned as
  313.    usual, and the count'th string is the remainder, unsplit.  So
  314.     split("-", "really-long-dylan-identifier", count: 3)
  315.    returns values("really", "long", "dylan-identifier").  If
  316.    remove-empty-items is true, empty items aren't counted.
  317.  
  318.    Case sensitive determines if the regexp for the delimiter should be
  319.    considered case sensitive or not; it defaults to
  320.    case-insensitive. Start: and end: indicate what part of the big
  321.    string should be looked at for delimiters.  They default to the
  322.    entire string.  For instance,
  323.     split("-", "really-long-dylan-identifier", start: 8)
  324.    returns values("really-long", "dylan", "identifier").  Caveat:
  325.    Unlike Perl, empty regular expressions are never legal regular
  326.    expressions, so there is no way to split a string into a #rest
  327.    sequence-of-characters.  Of course, in Dylan this is not a useful
  328.    thing to do, so this is not really a problem.
  329.  
  330. make-splitter                                   [Generic Function]
  331.     (pattern :: <string>, #key case-sensitive)
  332.     => an anonymous splitter
  333.        method (big-string, #key count, remove-empty-items,
  334.            start, end) => buncha-strings
  335.    Does what you would expect.
  336.  
  337. join                                            [Generic Function]
  338.     (delimiter :: <string>, #rest strings) => big-string
  339.    Does the opposite of a split.
  340.     join(":", word1, word2, word3)
  341.    is equivalent to
  342.     concatenate(word1, ":", word2, ":", word3)
  343.    (and no more efficient)  Note that there is no make-joiner.
  344.  
  345.  
  346.  
  347. Substring-search
  348.  
  349. Substring search contains methods for searching for fixed substrings
  350. rather than general regular expressions.  It is as similar to the
  351. regular expression module as we could make it.  Substring functions
  352. work only on byte strings, and are always case sensitive.  These
  353. functions were taken from the Collection-extensions library shipped in
  354. Mindy 1.1, but the parameters, keywords, and return values have
  355. changed significantly since then.
  356.  
  357. substring-position                              [Generic Function]
  358.     (big-string, search-for-string, #key start, end)
  359.     => position-or-false;
  360.    Returns the position of the search-for-string in the big-string (or
  361.    that portion of the big-string specified by start: and end:).  This
  362.    search is always case sensitive.
  363.  
  364.    This function uses the Boyer-Moore algorithm for long strings, and
  365.    a simple dumb search for short strings.  It should yield good
  366.    performance under all circumstances.
  367.  
  368. make-substring-positioner (search-for-string)   [Generic Function]
  369.  => an anonymous positioner
  370.     method (big-string, #key start, end) => position-or-false
  371.    Does the obvious.
  372.  
  373. substring-replace                               [Generic Function]
  374.     (big-string, search-for-string, replace-with-string,
  375.      #key count, start, end)
  376.     => replaced-string
  377.    Replaces the substring, or the first count instances of it if
  378.    count: is specified.  Note this function does not support start: or
  379.    end:.
  380.  
  381. make-substring-replacer                         [Generic Function]
  382.     (search-for :: <byte-string>, #key replace-with)
  383.     => an anonymous function replacer that is either
  384.        method (big-string, #key count, start, end) => new-string
  385.        or
  386.        method (big-string, replace-with-string, #key count, start, end)
  387.    Does the obvious.
  388.  
  389.  
  390.  
  391. Known bugs
  392.  
  393. Regular-expressions will do unpredictable things if given bad
  394. arguments.  (ie, a string that isn't a legal regular expression)
  395. Sometimes it'll crash, and sometimes it'll merily chug away and
  396. return crazy answers.
  397.  
  398. The regexp parser will happily accept a "quantified assertion," which
  399. isn't technically a legal regexp.  However, both regular and compiled
  400. matching will handle it as one intuitively thinks it should be
  401. handled.  (An example of a quantified assertion would be "^*", which
  402. matches "any number of beginning of line".  Since "*" means "0 or
  403. more", "^*" is interpretted to mean "", which is how one would
  404. intuitively belive it should be interpretted.)
  405.